﻿module Rendering

open System
open System.Windows
open System.Windows.Media
open Dom
open StyledElements
open HtmlDom
open Lines
open Boxes
open Layout
open RenderingContext


(*
    Rendering: 
    - converts parent-relative box positions to viewport-absolute
    - draws
    - register area

*)

// used for debugging layout
let outline (ctx:RenderingContext) width height =
    let pen = System.Windows.Media.Pen(Windows.Media.SolidColorBrush(Media.Colors.Azure), 1.0)
    do pen.DashStyle <- Windows.Media.DashStyles.Dash
    do ctx.context.DrawRectangle(null, pen, new Rect(ctx.pos, new Size(float(width), float(height))))

let renderElemBox boxWidth boxHeight (elem:IStyledElement) (c:RenderingContext) =
    let style = elem.computedStyle()
    // cheating! we average the border
    let borderWidth = 
        [style.borderTopWidth;style.borderBottomWidth;style.borderLeftWidth;style.borderRightWidth]
        |> List.map float
        |> List.average
        |> int

    let backgroundWidth = boxWidth - borderWidth
    let backgroundHeight = boxHeight - borderWidth

    // Draw border
    let borderTopLeft = 
        Point(c.pos.X + float(borderWidth)/2.0, 
              c.pos.Y + float(borderWidth)/2.0)
     
    // border coordinates are for the *middle* of the border
    
    let size = new Size(float(backgroundWidth), float(backgroundHeight))
    let rect = new Rect(borderTopLeft, size)
    // cheating! using top color
    let color = style.borderTopColor
    if borderWidth > 0 || style.backgroundColor<>Media.Colors.Transparent
    then do
        let brush = if style.backgroundColor=Media.Colors.Transparent
                    then null
                    else new Media.SolidColorBrush(style.backgroundColor)
        do c.context.DrawRectangle(brush, 
            Pen(
                Windows.Media.SolidColorBrush(color),  
                float(borderWidth)), rect)


// context is parent context
let rec renderLayout ((x,y),layout) (c:RenderingContext) =
    match layout with
    | ElementBoxLayout(BoxSize(width, height), elem, children) ->
        let ctx = c.move(x,y)        
        do outline ctx width height
        do renderElemBox width height elem ctx
        do renderLayoutChildren children ctx 
    | BoxLayout(BoxSize(width, height), children) ->
        let ctx = c.move(x,y)
        do renderLayoutChildren children ctx 
    | ReplacedContentLayout(BoxSize(width, height), elem) ->
        let ctx = c.move(x,y)
        do elem.render(ctx)
    | TextBoxLayout(sizedText) ->
        let ctx = c.move(x,y)
        do outline ctx sizedText.widthIncludingTrailingWhitespace sizedText.height
        do c.context.DrawText(sizedText.formattedText, ctx.pos)                      
    | NoLayout -> ()

and renderLayoutChildren children  (c:RenderingContext) =    
    for child in children do
        renderLayout child c


let render (doc:Document) (viewportSize:int*int) (c:RenderingContext) = 
    let width, height = viewportSize
    let availWidth = max width 600
    let layout = layoutRoot (doc.documentElement) availWidth
    renderLayout ((0,0),layout) c 
    layout
